package linhnv.app;

import java.io.IOException;
import java.io.InputStream;

import java.io.Serializable;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.HttpGet;

import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

public class HttpCommunication implements Serializable{
	
	/**
	 * Set default version for Serializable
	 */
	private static final long serialVersionUID = 1L;
	private String postGetURL = null;
	
	// Object

	private long contentLength;
	private Header contentHeader;
	
	private int httpFlag = 0;
	private boolean responseFlag = false;
	
	/**
	 * Prefix for write log
	 */
	private static final String TAG = "ThuNA - HttpCommunication";
	
	
	/**
	 * 
	 * @param context Input from a Activity
	 */
	public HttpCommunication() {
		// TODO Auto-generated constructor stub
		// Create HashMap
		
	}
	
	/**
	 * Get data from server with
	 * 
	 * function getHttpError() return: 
	 * 0. Correct
	 * 1. Client Protocol Exception
	 * 2. Socket or Connection TimeOut Exception
	 * 3. IO Exception, when response is error
	 * 
	 * @param url
	 * @return HttpResponse
	 */
	private HttpResponse httpGet(String url){
		HttpParams httpParameters = new BasicHttpParams();
        // Set the timeout in milliseconds until a connection is established.
        HttpConnectionParams.setConnectionTimeout(httpParameters, Constant.CONNECTION_TIMEOUT);
        // Set the default socket timeout (SO_TIMEOUT) 
        // in milliseconds which is the timeout for waiting for data.
        if(Constant.CONNECTION_TIMEOUT < Constant.SOCKET_TIMEOUT){
        	HttpConnectionParams.setSoTimeout(httpParameters, Constant.SOCKET_TIMEOUT);
        }
        
  		// Create the httpClient
		DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
		// Set data
		if(null != Constant.URL_USER){
			httpClient.setCredentialsProvider(credentialsProvider());
		}
		
        // Prepare a request object
        HttpGet httpGet = new HttpGet(url);
        // Execute HTTP Post Request
        HttpResponse response = null;
        
		try {
			response = httpClient.execute(httpGet);
			
			setHttpError(0);
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			// Write-log
			ShowLog.showLogError(TAG, "httpGet :: ClientProtocolException: " + e.getLocalizedMessage());
			
			setHttpError(1);
		} catch (SocketTimeoutException e) {
			// TODO: handle exception
			// Write-log
			ShowLog.showLogError(TAG, "httpGet :: SocketTimeoutException: " + e.getLocalizedMessage());
			
			setHttpError(2);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			// Write-log
			ShowLog.showLogError(TAG, "httpGet :: IOException: " + e.getLocalizedMessage());
			
			setHttpError(3);
		} finally{
			// Clear object after using
	        httpGet = null;
	        // Clear connect and request, response data
	        httpClientCleaner(httpClient);
		}
		
        return response;
	}
	
	/**
	 * return this.isLogin;
	 * Create CredentialsProvider
	 * @return CredentialsProvider
	 */
	private CredentialsProvider credentialsProvider(){
		CredentialsProvider credsProvider = new BasicCredentialsProvider();
    	credsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
    		 new UsernamePasswordCredentials(Constant.URL_USER, Constant.URL_PASSWORD));
    	
    	return credsProvider;
	}
	
	/**
	 * Clear connection and request of response data
	 * @param httpClient
	 */
	private void httpClientCleaner(DefaultHttpClient httpClient){
        httpClient.clearRequestInterceptors();
        httpClient.clearResponseInterceptors();
        httpClient.getConnectionManager().closeExpiredConnections();
        //httpClient.getConnectionManager().shutdown();
	}	
	
	/**
	 * Get data from server
	 * @return InputStream
	 */
	public InputStream get(){
		//Get time for start get
		ShowLog.showLogTime(TAG, "get :: Start get");

		HttpResponse response = httpGet(postGetURL);
		InputStream result = getEntity(response);
		
		if(null != response){
			// Result get data from API wrong
			if(response.getStatusLine().getStatusCode() != 200){
				setResponseFlag(true);
			}else{
				setResponseFlag(false);
			}
		}
		// Clear response after using
		response = null;
		
	    //Get time for end get
	    ShowLog.showLogTime(TAG, "get :: End get");
	    // Write-log
	    ShowLog.showLogInfo(TAG, "get :: result error flag status is " + getResponseFlag());
	    
	    return result;
		
	}	
	
	/**
	 * Get Entity Content, include setter length and type
	 * @param response
	 * @return input stream
	 */
	private InputStream getEntity(HttpResponse response){
		InputStream result = null;
		
		if(null == response){
			return null;
		}
		
			HttpEntity entity = response.getEntity();
			
	    	if (null != entity) {
	    		
	    		try {
	    			// Set content length and content header
	    			setContentLength(entity.getContentLength());
	    			setContentHeader(entity.getContentType());
	    			//entity.getContentEncoding(); // encode of content
	  
					result = entity.getContent();
				} catch (IllegalStateException e) {
					// TODO Auto-generated catch block
					// Write-log
					ShowLog.showLogError(TAG, "getEntity :: IllegalStateException with message " + e.getLocalizedMessage());
					
					setHttpError(1);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					// Write-log
					ShowLog.showLogError(TAG, "getEntity :: IOException with message " + e.getLocalizedMessage());
					
					setHttpError(3);
				}
				
				
	        }
	    	
	    	return result;
		//}
	}
	
	
	
	public void setUrl(boolean hasUrlLinkFull, String url){
		
		if(hasUrlLinkFull){
			postGetURL = url;
			
			// Write-log
			ShowLog.showLogInfo(TAG, "setUrl :: " + postGetURL + " - Flag :: " + hasUrlLinkFull);
		}else{
			setUrl(url);
		}
	}
	
	/**
	 * Set URL post to server
	 * @param url
	 */
	public void setUrl(String url){
		if(Constant.IS_REAL){
			postGetURL = Constant.URL_REAL + URLDecoder.decode(url);
		}else{
			postGetURL = Constant.URL + URLDecoder.decode(url);
		}
		
		// Write-log
		ShowLog.showLogInfo(TAG, "setUrl :: " + postGetURL);
	}
	
	
	
	/* Setter and Getter in object */
	/* =========================== */
	/**
	 * @param contentLength the contentLength to set
	 */
	private void setContentLength(long contentLength) {
		this.contentLength = contentLength;
	}

	/**
	 * @return the contentLength
	 */
	public long getContentLength() {
		return contentLength;
	}

	/**
	 * @param contentHeader the contentHeader to set
	 */
	private void setContentHeader(Header contentHeader) {
		this.contentHeader = contentHeader;
	}

	/**
	 * @return the contentHeader
	 */
	public Header getContentHeader() {
		return contentHeader;
	}
	
	/**
	 * Set httpFlag
	 * @param httpFlag
	 */
	private void setHttpError(int httpFlag){
		this.httpFlag = httpFlag;
	}
	/**
	 * Get httpFlag
	 * @return Integer 
	 */
	public int getHttpError(){
		return this.httpFlag;
	}
	
	/**
	 * @param responseFlag the responseFlag to set
	 */
	private void setResponseFlag(boolean responseFlag) {
		this.responseFlag = responseFlag;
	}

	/**
	 * @return the responseFlag
	 */
	public boolean getResponseFlag() {
		return responseFlag;
	}
	

}